const WebSocket = require('ws');
const fs = require('fs');
const https = require("https");
const { assert } = require('console');

const PUSHER_FILE = __dirname+"/pusher_clnt.json";
const pushers = {};
const ws2puhser = {};

function reload(){
    try{
        JSON.parse(fs.readFileSync("pusher_clnt.json"))["pushers"].forEach(element => {
            assert(element.hasOwnProperty("id"));
            assert(element.hasOwnProperty("key"));
            pushers[element["id"]] = {
                "key": element["key"],
                "ws": null,
                "last_active": 0
            };
        });
    }catch{
        fs.writeFile(PUSHER_FILE, JSON.stringify({
            "pushers": []
        }),(err)=>{console.error(err)});
    }
}

reload();

function save() {
    const to_save = [];
    for (const id in pushers) {
        to_save.push({
            "id": id,
            "key": pushers[id]["key"]
        });
    }
    fs.writeFile(PUSHER_FILE, JSON.stringify({
        "pushers": to_save
    }),(err)=>{console.error(err)});
}


var wsserv = null;

function start(port, httpsOptions) {
    if(wsserv!=null){
        stop();
    }
    if(httpsOptions==null){
        wsserv = new WebSocket.Server({ port: port });
    }else{
        const httpsServer = https.createServer(httpsOptions, (req, res) => {
            res.writeHead(200);
            res.end("wss");
        });
        httpsServer.listen(port);
        wsserv = new WebSocket.Server({ server: httpsServer });
    }
    wsserv.on('connection', work);
}

function stop() {
    wsserv.close();
    wsserv = null;
}

function ask_push(id) {
    if(id in pushers && pushers[id]["ws"]!=null){
        pushers[id]["ws"].send(JSON.stringify({
            "op": "push"
        }));
        return true;
    }else{
        return false;
    }
}

function ask_stop(id) {
    if(id in pushers && pushers[id]["ws"]!=null){
        pushers[id]["ws"].send(JSON.stringify({
            "op": "stop"
        }));
        return true;
    }else{
        return false;
    }
}

function work(ws) {
    console.log("[WSS] connection!")
    ws.on('close', function close() {
        const id = ws2puhser[ws];
        console.log("[WSS] Close "+id);
        if(id in pushers) {
            pushers[id]["ws"] = null;
        }        
        delete ws2puhser[ws];
    });
    ws.on('message', function incoming(message) {
        var data = null;
        try{
            data = JSON.parse(message);
        }catch{
            ws.send(JSON.stringify({
                "code": -3,
                "msg": "not json"
            }));
            console.log("[WSS] Invalid JSON");
            ws.close();
            return;
        }
        const id = data["id"];
        if(!(id in pushers) || pushers[id]["key"]!=data["key"]) {
            ws.send(JSON.stringify({
                "code": -1,
                "msg": "unauthorized"
            }));
            console.log("[WSS] Unathorized");
            ws.close();
        }
        ws2puhser[ws] = id;
        pushers[id]["ws"] = ws;
        pushers[id]["last_active"] = Date.now();
        if(data["op"]==="hb"){
            ws.send(JSON.stringify({
                "code": 0,
                "msg": "hb ok"
            }));
        }else if(data["op"]==="push_req"){
            ws.send(JSON.stringify({
                "code": 0,
                "msg": "allow push"
            }));
        }else if(data["op"]==="push"){
            ws.send(JSON.stringify({
                "code": 0,
                "msg": "push recv"
            }));
        }else if(data["op"]==="stop"){
            ws.send(JSON.stringify({
                "code": 0,
                "msg": "stop recv"
            }));
        }else{
            ws.send(JSON.stringify({
                "code": -2,
                "msg": "unknown operation"
            }));
        }
    });
}

function add_client(id, key) {
    if(!(id in pushers)){
        pushers[id] = {
            "key": key,
            "ws": null
        };
        save();
        return true;
    }else{
        return false;
    }
}

function del_client(id, key) {
    if(id in pushers){
        ask_stop(id);
        delete pushers[id];
        save();
        return true;
    }else{
        return false;
    }
}


function get_status(id) {
    if(id in pushers){
        return pushers[id];
    }else{
        return null;
    }
}

function get_all_status() {
    return pushers;
}

function check_key(id, key) {
    if(id in pushers) {
        return pushers[id]["key"] === key;
    }
    return false;
}

module.exports = {
    reload: reload,
    start: start,
    stop: stop,
    ask_push: ask_push,
    ask_stop: ask_stop,
    add_client: add_client,
    del_client: del_client,
    get_status: get_status,
    get_all_status: get_all_status,
    check_key: check_key
}